Skip to main content

Docker Build

docker-build (VMID 112, 10.0.0.12) is the CI build server. It runs the self-hosted CI runners and the private Docker registry that every other VM pulls its images from.

Playbookansible/hetzner-main/setup-docker-build.yml
Registry stackansible/hetzner-main/docker-build-apps/docker-registry/
Make targetssetup-docker-build, update-docker-build, setup-gitea-runner, update-gitea-runner, deploy-docker-registry, enroll-wazuh-docker-build
SecretsDocker Registry Password, ABAIR Github Runner, Gitea Runner Registration Token

CI runners​

Two runners work independently on the same VM. Each has its own Linux user and SSH key pair.

GitHub Actions runnerGitea Actions runner
Linux usergithub-runnergitea-runner
Registered withthe phonlab-tcd GitHub organisationGitea at https://gitea-direct.abair.ie
Versionactions-runner 2.316.1act_runner 0.2.11
ServiceGitHub's svc.sh systemd serviceact_runner.service
LabelsGitHub defaultsself-hosted:host (jobs run directly on the VM, not in a container), name docker-build-gitea
Set up bymake setup-docker-buildmake setup-gitea-runner (the gitea-runner tag)

Both users are in the docker group and are logged in to the registry, so workflows can docker build and docker push without extra credentials. Node.js 20 is installed for JavaScript actions such as actions/checkout.

The Gitea runner registers with gitea-direct.abair.ie, which skips Cloudflare, rather than gitea.abair.ie. Cloudflare cuts off the runner's long-poll connections. See Secops → Gitea.

Deploy keys​

Each runner's SSH public key is authorized for the deploy user on the VMs it deploys to. The other playbooks fetch the keys straight from docker-build at run time, so nothing is copied by hand:

Target VMGitHub runner keyGitea runner key
services-useryesno
services-staffyesyes
api-gatewayyesno

A deploy step in CI is then a plain SSH command, for example ssh deploy@10.0.0.19 "cd /opt/apps/<app> && docker compose pull && docker compose up -d".

Registering a runner​

Registration only happens on the first run. The playbook skips it once a runner is configured.

  • GitHub: the token must be a short-lived runner registration token, not a personal access token. Get one from the organisation's Actions → Runners → New self-hosted runner page. The ABAIR Github Runner item in Vaultwarden will have expired, so pass a fresh token:
    make setup-docker-build TARGET_GITHUB_TOKEN=<fresh token>
  • Gitea: create a registration token under Site Administration → Actions → Runners, store it in Vaultwarden as Gitea Runner Registration Token, then run make setup-gitea-runner.

Docker registry​

Imageregistry:2, container docker-registry
Address10.0.0.12:5000 inside the network, registry.abair.ie through the webserver
Authhtpasswd, user admin, password Docker Registry Password
Storage/opt/apps/docker-registry/data
Deploymake deploy-docker-registry

The registry serves TLS itself, using certificates in /opt/apps/docker-registry/certs/. Clients inside the network connect by IP, so every VM lists 10.0.0.12:5000 as an insecure registry in /etc/docker/daemon.json. The auth/ and certs/ directories were copied by hand from the legacy services VM, and Ansible doesn't create them.

The registry holds the only copy of the built images. On a rebuild, restore its data from the VM backup before configuring the other VMs, or their docker compose pull will fail.

Maintenance​

  • A root cron job runs docker system prune -af --filter until=24h at 03:00 every day, to keep the build cache from filling the 50 GB disk.
  • Docker restarts on every setup or update run, which briefly restarts the registry.
  • This VM has no UFW firewall configured.
  • Don't resize it with terraform apply. Use the qm set procedure described on the Webserver page.